﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Text.RegularExpressions;

namespace Webcrawler
{
	public class Crawler
	{
		private Uri uri = null;
		private string headers = "";
		private string content = "";

		private bool thisDomainOnly = false;

		private List<Link> links = new List<Link>();
		private DateTime timestamp;

		public string Url
		{
			get { return uri.AbsoluteUri; }
		}
		
		public List<Link> Links
		{
			get { return links; }
		}

		public string Content
		{
			get { return content; }
		}

		public string Headers
		{
			get { return headers; }
		}

		public DateTime Timestamp
		{
			get { return timestamp; }
		}

		public int CrawlPage(string url)
		{
			int result = -1;
			this.uri = this.ValidateAddress(url);
			
			if (this.uri != null)
			{
				result = this.CrawlPage();
			}

			return result;
		}

		public int CrawlPage(string url, bool thisDomainOnly)
		{
			int result = -1;
			this.uri = this.ValidateAddress(url);
			this.thisDomainOnly = thisDomainOnly;

			if (this.uri != null)
			{
				result = this.CrawlPage();
			}

			return result;
		}

		public int CrawlPage()
		{
			int count = -1;
			using (WebClient client = new WebClient())
			{
				// Download til lokal fil
				//client.DownloadFile(website, @"C:\localfile.html");
				this.timestamp = DateTime.Now;

				//Console.WriteLine(this.uri.AbsoluteUri);
                try
                {
                    // Bare hent indholdet
                    this.content = client.DownloadString(this.uri);
                    // Får headers
                    this.headers = client.ResponseHeaders.ToString();

                    if (this.content.Length > 0)
                    {
                        count = 0;

                        try
                        {
                            //Console.WriteLine("Headers:");
                            //Console.WriteLine("----------------------");
                            //Console.WriteLine(this.headers);
                            //Console.WriteLine("----------------------");
                            //Console.WriteLine("");

                            //Console.WriteLine("HTML:");
                            //Console.WriteLine("----------------------");
                            //Console.WriteLine(this.content);
                            //Console.WriteLine("----------------------");

                            MatchCollection m1 = Regex.Matches(this.content, "(<a.*?href=[\"'](.*?)[\"'].*?>(.*?)</a>)", RegexOptions.Singleline);
                            MatchCollection m2 = Regex.Matches(this.content, "(<iframe.*?src=[\"'](.*?)[\"'].*?>(.*?)</iframe>)", RegexOptions.Singleline);
                            MatchCollection m3 = Regex.Matches(this.content, "(<frame.*?src=[\"'](.*?)[\"'].*?[/]*>)", RegexOptions.Singleline);

                            count += FetchContent(m1);
                            count += FetchContent(m2);
                            count += FetchContent(m3);

                        }
                        catch (Exception e)
                        {
                            count = -1;
                            Console.WriteLine("Match error: " + e.ToString());
                        }
                    }
                }
                catch (WebException e)
                {
                    count = -1;
                    Console.WriteLine("Could not crawl page \"" + this.uri.AbsoluteUri + "\" (" + e.Message + ")");

                    // Shut up with that warning!!!!!!
                    e.ToString();
                }
			}

			return count;
		}

		private int FetchContent(MatchCollection m1)
		{
			// Loop alle svarene
			int i = 0;
			foreach (Match m in m1)
			{
				string url = m.Groups[2].ToString();
				string text = m.Groups[3].ToString();
				bool sameDomain = false;

                if (url.Length > 0)
                {
                    if (url.Substring(0, 1) == "#")
                    {
                        url = null;
                    }

                    if (url != null && url.Length > 0)
                    {
                        //Console.WriteLine(this.uri.AbsoluteUri);
                        if (url.Contains(this.uri.Host))
                        {
                            sameDomain = true;
                            Uri newUrl = new Uri(this.uri, url);
                            url = newUrl.AbsoluteUri;
                        }
                        else if (url.Length <= 8 || (url.Substring(0, 7) != "http://" && url.Substring(0, 8) != "https://" && url.Substring(0, 4) != "www."))
                        {
                            sameDomain = true;
                            //Console.WriteLine(this.uri.AbsoluteUri);
                            Uri newUrl = new Uri(this.uri, url);
                            url = newUrl.AbsoluteUri;
                            //Console.WriteLine(url);



                            /*
                            Console.WriteLine("hihi: " + lala.AbsolutePath);

                            string newUrl = "http://" + this.uri.Host;
                            if (url.Substring(0, 1) == "/")
                            {
                                newUrl += url;
                            }
                            else
                            {
                                //Console.WriteLine("Before URL: " + url);
                                string[] e = uri.PathAndQuery.Trim('/').Split('/');
                                //Console.WriteLine("Length: " + e.Length);
                                //Console.WriteLine("0: " + e[0]);
                                if (e.Length > 0)
                                {
                                    if (e.Length > 1)
                                    {
                                        //Console.WriteLine("her");
                                        newUrl += String.Join("/", e, 0, (e.Length - 2));
                                        newUrl += url;
                                    }
                                    else
                                    {
                                        //Console.WriteLine("0: " + e[0]);
                                        newUrl += "/" + e[0] + "/" + url;
                                    }
                                }
                            }

                            url = newUrl;
                             */
                        }

                        string[] e = url.Split('/');
                        if (e.Length > 0 && e[e.Length - 1].Length > 0 && !e[e.Length - 1].Contains('.') && url.Substring(url.Length - 1, 1) != "/")
                        {
                            url = url + "/";
                        }


                        //Console.WriteLine("Final URL: " + url);

                        if (!this.thisDomainOnly || (this.thisDomainOnly && sameDomain))
                        {

                            Link link = new Link(url, text);
                            this.links.Add(link);

                            //Console.Write("#" + i + ": ");
                            //Console.Write("'" + url + "'");
                            //Console.WriteLine(" (" + text + ")");

                            i++;
                        }
                    }
                }
			}

			return i;
		}

		private Uri ValidateAddress(string url)
		{
			Uri u = null;
			if (url.Length >= 8)
			{
				if ((url.Substring(0, 7) != "http://" && url.Substring(0, 8) != "https://") || url.Substring(0, 4) == "www.")
				{
					url = "http://" + url;
				}
			}
			else
			{
				url = "http://" + url;
			}

            string[] e = url.Split('/');
            if (e.Length > 0 && e[e.Length - 1].Length > 0 && !e[e.Length - 1].Contains('.') && url.Substring(url.Length - 1, 1) != "/")
            {
                url = url + "/";
            }

			try
			{
				u = new Uri(url);
			} catch (UriFormatException ex) {
                // Shut up with that warning!!!!!!
                ex.ToString();
            }

			return u;
		}
	}
}
